package com.vedana.bankmobile.protobuf;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import com.google.protobuf.Descriptors.MethodDescriptor;
import com.google.protobuf.Message;
import com.google.protobuf.RpcCallback;
import com.google.protobuf.RpcController;
import com.vedana.bankmobile.shared.Account;
import com.vedana.bankmobile.shared.Customer;
import com.vedana.bankmobile.shared.Operation;
import com.vedana.bankmobile.shared.protobuf.BankProto.AccountListRequest;
import com.vedana.bankmobile.shared.protobuf.BankProto.AccountListResponse;
import com.vedana.bankmobile.shared.protobuf.BankProto.AccountMsg;
import com.vedana.bankmobile.shared.protobuf.BankProto.BankMobileService;
import com.vedana.bankmobile.shared.protobuf.BankProto.CustomerListRequest;
import com.vedana.bankmobile.shared.protobuf.BankProto.CustomerListResponse;
import com.vedana.bankmobile.shared.protobuf.BankProto.CustomerMsg;
import com.vedana.bankmobile.shared.protobuf.BankProto.OperationListRequest;
import com.vedana.bankmobile.shared.protobuf.BankProto.OperationListResponse;
import com.vedana.bankmobile.shared.protobuf.BankProto.OperationMsg;
import com.vedana.bankmobile.shared.protobuf.serializers.AccountSerializer;
import com.vedana.bankmobile.shared.protobuf.serializers.CustomerSerializer;
import com.vedana.bankmobile.shared.protobuf.serializers.OperationSerializer;

/**
 * BankMobile service : protobuf RPC adapter
 * 
 * @author Didier MOISE
 *
 */
public class BankMobileProtoHandler extends BankMobileService {
	private com.vedana.bankmobile.services.BankMobileService service = new com.vedana.bankmobile.services.BankMobileServiceImpl();
	
	/**
	 * Handle protobuf request / response for servlet.
	 * 
	 * @param os servlet output stream
	 * @param is servlet input stream
	 * 
	 * @throws IOException I/O exception
	 */
	void handle(final OutputStream os, final InputStream is) throws IOException {
		RpcCallback<Message> done = new RpcCallback<Message>() {
			DataOutputStream dos = new DataOutputStream(os);

			public void run(Message content) {
				try {
					dos.writeInt(content.getSerializedSize());
					content.writeTo(dos);
					dos.flush();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		DataInputStream dis = new DataInputStream(is);
		int index = dis.readInt();
		MethodDescriptor method = getDescriptor().getMethods().get(index);
		byte[] array = new byte[dis.readInt()];
		dis.readFully(array);
		Message request = getRequestPrototype(method).newBuilderForType()
				.mergeFrom(array).build();
		callMethod(method, null, request, done);
	}

	@Override
	public void getOperationList(RpcController controller,
			OperationListRequest request, RpcCallback<OperationListResponse> done) {
		List<Operation> operations = service.getAllOperations(request.getAccountId());
		
		// Build protobuf response		
		List <OperationMsg> operationMsgs = OperationSerializer.writeListToMsg(operations);
		OperationListResponse msg = OperationListResponse.newBuilder().addAllOperations(operationMsgs).build();
		
		done.run(msg);
	}


	@Override
	public void getCustomerList(RpcController controller,
			CustomerListRequest request, RpcCallback<CustomerListResponse> done) {
		
		List<Customer> customers = service.getCustomerList(request.getUserId());
		
		// Build protobuf response
		List<CustomerMsg> customerMsgs = CustomerSerializer.writeListToMsg(customers); 
		CustomerListResponse msg =  CustomerListResponse.newBuilder().addAllCustomers(customerMsgs).build();
		
		done.run(msg);
	}

	@Override
	public void getAccountList(RpcController controller,
			AccountListRequest request, RpcCallback<AccountListResponse> done) {
		List<Account> accounts = service.getAccountList(request.getCustomerId());
		
		// Build protobuf response		
		List<AccountMsg> accountMsgs = AccountSerializer.writeListToMsg(accounts);		
		AccountListResponse msg = AccountListResponse.newBuilder().addAllAccounts(accountMsgs).build();
		
		done.run(msg);
	}
}
